const crypto = require("crypto");
const getRawBody = require("raw-body");
const typeis = require("type-is");
const { exec } = require("child_process");

/**
 * Get sha256 hmac signature
 * @param {String} data data
 * @param {String} secret secret
 */
function sign(data, secret = "xxx") {
    return crypto
        .createHmac("sha256", secret)
        .update(data)
        .digest("hex");
}
/**
 * Exec command
 * @param {String} command command
 * @param {String} options options
 */
function execCommand(command, options) {
    return new Promise((resolve, reject) => {
        exec(command, options, (error, stdout, stderr) => {
            if (error) {
                reject(error);
            } else {
                resolve({
                    stdout: stdout.toString(),
                    stderr: stderr.toString()
                });
            }
        });
    });
}

module.exports = async (ctx, next) => {
    const sig = ctx.get("X-Gogs-Signature");
    const event = ctx.get("X-Gogs-Event");
    const id = ctx.get("X-Gogs-Delivery");

    if (sig && event && id) {
        // gogs signature
        const buf = await getRawBody(ctx.req);
        if (sig !== sign(buf)) {
            throw new Error("Gogs Hook Signature Is Wrong");
        }
        if (!typeis(ctx.req, ["application/json"])) {
            throw new Error("Gogs Hook Context-Type Must Be application/json");
        }

        // master branch
        const post = buf.toString() ? JSON.parse(buf.toString()) : {};
        if (post.ref !== "refs/heads/master") {
            throw new Error("Gogs Hook Must Be Master Branch");
        }

        // gogs command
        const message = post.commits[0].message;
        if (message.indexOf("@pull") !== -1) {
            await execCommand("git pull");
        }
        if (message.indexOf("@yarn") !== -1) {
            await execCommand("yarn install");
        }
        if (message.indexOf("@build") !== -1) {
            await execCommand("npm run build");
        }
        if (message.indexOf("@start") !== -1) {
            await execCommand("pm2 start pm2.json");
        }
        if (message.indexOf("@restart") !== -1) {
            await execCommand("pm2 restart pm2.json");
        }
        if (message.indexOf("@stop") !== -1) {
            await execCommand("pm2 stop pm2.json");
        }
        ctx.body = {
            errmsg: "ok",
            errcode: 0
        };
    } else {
        await next();
    }
};
